#pragma once
#include <unordered_map>
#include "message.hpp"
#include <mutex>
/*
    为了减少判断不同消息类型的分支语句
    故引入派发接口
*/

namespace rpc
{
    class Callback
    {
    public:
        using ptr = std::shared_ptr<Callback>;
        virtual void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) = 0;
    };

    template <typename T>
    class CallbackT : public Callback
    {
    public:
        using ptr = std::shared_ptr<CallbackT<T>>;
        using MessageCallBack = std::function<void(const BaseConnection::ptr &conn, std::shared_ptr<T> &ptr)>;
        CallbackT(const MessageCallBack &cb) : _handler(cb) {}
        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg) override
        {
            auto type_msg = std::dynamic_pointer_cast<T>(msg);
            if (type_msg == nullptr)
            {
                LOG(ERROR, "消息类型转换失败");
            }
            _handler(conn, type_msg);
        }

    private:
        MessageCallBack _handler;
    };

    class Dispatcher
    {
    private:
        std::mutex _mutex;
        std::unordered_map<MType, Callback::ptr> _handlers;

    public:
        using ptr = std::shared_ptr<Dispatcher>;
        template <typename T>
        void registerHandler(MType type, const typename CallbackT<T>::MessageCallBack &handler)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto cb = std::make_shared<CallbackT<T>>(handler);
            _handlers.insert(std::make_pair(type, cb));
        }

        void onMessage(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _handlers.find(msg->mtype());
            if (it != _handlers.end())
            {
                return it->second->onMessage(conn, msg);
            }

            // 没有此消息类型，非正常情况
            conn->shutdown();
            return;
        }
    };
}